''Single_Servo_Spin
''Author: Gavin Garner
''November 17, 2008  
''This program demonstrates how to control a single RC servomotor by dedicating a cog to output signal pulses using a simple
''Spin program. Once the "MoveMotor" method is running on a new cog, it continuously checks the value of the "position"
''variable in the main RAM (the value of which code running on any other cog can change at any time) and creates a steady
''stream of signal pulses with a high part that is equal to the "position" value times 10 microseconds in length
''and a low part that is 10ms in length. (This low part may need to be changed to 20ms depending on the brand of motor being
''used, but 10ms seems to work fine for Parallax/Futaba Standard Servos and gives a quicker response time than 20ms.) For
''higher position accuracy, refer to my Single_Servo_Assembly and Single_Servo_Counter demos.
'Notes:
' -To use this in your own Spin code, simply declare a "position" variable as a long, start running the "MoveMotor" method
'  in a new cog with the "cognew(@MoveMotor(<Pin>),@Stack)" line and copy and paste my "MoveMotor" method into your own code.
'  Whenever the "position" variable is changed (by any cog) the "MoveMotor" method will change the servo signals accordingly.
' -If you are using a Parallax/Futaba Standard Servo, the range of signal pulse widths is typically between 0.5-2.25ms, which
'  corresponds to "position" values between 50 (full clockwise) and 225 (full counterclockwise). This provides you with 175
'  units of position resolution across the full range of motion. You may need to experiment with changing the "position"
'  values a little to take advantage of the full range of motion for the specific RC servo motor that you are using. However,
'  you must be careful not to force the servo to try to move beyond its mechanical stops.
' -If you find that your propeller chip or servomotor stops working for no apparent reason, it could be that the motor is
'  sending inductive spikes back into the power supply or it is simply drawing too much current and resetting the
'  propeller chip. Adding a large capacitor (e.g.,1000uF) across the power leads of the servo motor or using separate power
'  sources for the propeller chip's 3.3V regulator and the servomotor's power supply will help to fix this.
 
CON
  _xinfreq=5_000_000            
  _clkmode=xtal1+pll16x                 'The system clock is set at 80MHz (this is recommended for optimal resolution)

VAR
  long position                         'The assembly program will read this variable from the main RAM to determine the
                                        ' servo signal's high pulse duration
  long Stack[5]                         'Alot some stack space for the cog running MoveMotor to use
  
{{PUB Demo                                
  cognew(MoveMotor(20),@Stack)           'Start a new cog and run the MoveMotor method on it that outputs pulses on Pin 7 
                                         
'The new cog that is started above continuously reads the "position" variable as it's changed by the example Spin code below
  repeat 
    position:=50                       'Start sending 1ms servo signal high pulses (100 * 10us = 1ms)                                                        
    waitcnt(clkfreq/8000+cnt)                'Wait for 1 second (1ms high pulses continue to be generated by the other cog)                                                                   
    position:=138                       'Start sending 1.38ms servo signal high pulses (Center position)                                                      
    waitcnt(clkfreq+cnt)                'Wait for 1 second (1.38ms high pulses continue to be generated by the other cog)                                                                     
    position:=50                        'Start sending 0.5ms servo signal high pulses (Clockwise position)                                                      
    waitcnt(clkfreq+cnt)                'Wait for 1 second (0.5ms high pulses continue to be generated by the other cog)      
    position:=225                       'Start sending 2.25ms servo signal high pulses (Counterclockwise position)                                                      
    waitcnt(clkfreq+cnt)                'Wait for 1 second (2.25ms high pulses continue to be generated by the other cog)      }}
    
                                                                                                                         
PUB MoveMotor(Pin, LOL)                              'This method outputs a continuous stream of servo signal pulses on "Pin"
  dira[Pin]~~                                   'Set the direction of "Pin" to be an output
  outa[Pin]~~                                 'Set "Pin" High
  waitcnt((clkfreq/100_000)*LOL+cnt)     'Wait for the specifed position (units = 10 microseconds)
  outa[Pin]~                                  'Set "Pin" Low
  waitcnt(clkfreq/100+cnt)                    'Wait 10ms between pulses


{Copyright (c) 2008 Gavin Garner, University of Virginia
MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and
this permission notice shall be included in all copies or substantial portions of the Software. The software is provided
as is, without warranty of any kind, express or implied, including but not limited to the warrenties of noninfringement.
In no event shall the author or copyright holder be liable for any claim, damages or other liablility, out of or in
connection with the software or the use or other dealings in the software.}                    